TACANManager = {
    C_EVENT_TACAN_USER_REMOVED = 'C_EVENT_TACAN_USER_REMOVED',
}

--[[
    TODO:
    从mission文件中提前录入被预设好的塔康, 并且登记单位.
    完善事件触发驱动的info更新机制

]]

do
    --================== Config ==================
    local Debug = false

    local DrawMapInfo = true
    local DrawInfoID = nil

    local DrawInfoCoord = {
        x=-297228,
        y=1000,
        z=234747,
    }

    local theatre = env.mission.theatre
    if theatre == 'GermanyCW' then
        DrawInfoCoord = {
            x=5152,
            y=1000,
            z=-746539-70000,
        }
    end


    local UnknownUserIndex = 1

    local Mode = {
        X = 'X',
        Y = 'Y',
    }

    local Usage = {
        AA = 'A/A',
        TR = 'T-R',
        REC = 'REC',
    }
    
    local CHANNEL_RANGE = {
        min = 1,
        max = 126,
    }

    local TACAN_USER_REMOVE_EVENT_FORM = {
        id = TACANManager.C_EVENT_TACAN_USER_REMOVED,
        time = nil,
        userName = nil
    }

    --================ Config end ================

    local AllChannels = {}
    local EventHandlerPool = {}
    local RegisteredUsers = {}

    --- table深度复制
	-- Usually this object is a table.
	-- See also: from http://lua-users.org/wiki/CopyTable
	-- @param object object to copy
	-- @return copy of object
    local function deepCopy(object)
		local lookup_table = {}
		local function _copy(object)
			if type(object) ~= "table" then
				return object
			elseif lookup_table[object] then
				return lookup_table[object]
			end
			local new_table = {}
			lookup_table[object] = new_table
			for index, value in pairs(object) do
				new_table[_copy(index)] = _copy(value)
			end
			return setmetatable(new_table, getmetatable(object))
		end
		return _copy(object)
	end

    -- 检查频率是否在有效范围内
    local function isFrequencyValid(channel)
        if not channel or channel == 'Null' then 
            return false 
        end

        return channel >= CHANNEL_RANGE.min and channel <= CHANNEL_RANGE.max
    end

    -- 获取一个可用频道
    local function getAvailableChannel(params)
        local channel = params.channel or 'Null'
        local mode = params.mode
        local reusable = params.reusable

        local channelID = channel..mode

        -- 若freq合法
        if isFrequencyValid(channel) then
            if not AllChannels[channelID] then return channel end
            if reusable then
                return channel
            end
        end

        -- 若freq不合法
        for i=CHANNEL_RANGE.min,CHANNEL_RANGE.max,1 do
            local newChannelID = i..mode
            
            if not AllChannels[newChannelID] then
                return i
            end

            if reusable and AllChannels[newChannelID].reusable then
                return i
            end
        end
        
        return channel
    end

    -- 获取已注册的用户
    local function getRegisteredUser(userName)
        if not userName then return end
        if type(userName)~='string' then return end

        return RegisteredUsers[userName]
    end

    -- 获取 "无线电用户被移除" 事件格式
    function TACANManager.getRadioUserRemovedEventForm(time,userName)
        local form = deepCopy(TACAN_USER_REMOVE_EVENT_FORM)
        form.time = time
        form.userName = userName
        return form
    end

    -- 将频道设置为可以多人使用
    function TACANManager.setReusable(channelID)
        if not channelID or not AllChannels[channelID] then
            return 
        end

        AllChannels[channelID].reusable = true
    end

    --@params table userName channel mode callSign usage reusable
    --@return registered channel with mode
    function TACANManager.registerChannel(params)
        local userName = params.userName
        local channel = params.channel or 'Null'
        local mode = params.mode or Mode.X
        local usage = params.usage
        local callSign = params.callSign
        local reusable = params.reusable

        -- 检查 userName
        if not userName or type(userName)~='string' then
            userName = 'UnknowUser-'..UnknownUserIndex
            UnknownUserIndex = UnknownUserIndex + 1
        end

        -- 检查 mode
        if not mode or (mode~=Mode.X and mode~=Mode.Y) then
            mode = Mode.X
        end

        -- 检查 callSign
        if not callSign or type(callSign)~='string' then
            callSign = ''
        end

        -- 检查 usage
        if not usage or (usage~=Usage.AA and usage~=Usage.TR and usage~=Usage.REC) then
            usage = Usage.TR
        end
        
        -- 规范 reusable
        if reusable then reusable = true end

        -- 强制注销旧频道（若存在）
        local registeredChannel = getRegisteredUser(userName)
        if registeredChannel then
            --如果重复申请就返回
            if registeredChannel == channel then return channel end

            TACANManager.deregisterChannel(userName)
        end

        local channelID = channel..mode
        local newChannel = getAvailableChannel(params)
        local newChannelID = newChannel..mode

        if newChannel ~= channel then

            local errMsg = 'TACANManager - registerChannel: ['..userName..': '..channelID..'] Input channel error, set to new channel: '

            if Localizations then
                errMsg = 'TACANManager - registerChannel: ['..userName..': '..channelID..'] '
                errMsg = errMsg .. Localizations:translate('Input channel error, set to new channel: ', 'cn')
            end
            
            channel = newChannel
            channelID = newChannelID
            errMsg = errMsg .. channelID

            if Debug then
                Utils.Debug(errMsg)
            end
        end
        
        if Debug then
            Utils.Debug('TACANManager - registerChannel: '..channelID..' for '..userName)
        end

        AllChannels[channelID] = AllChannels[channelID] or {users = {}}
        table.insert(AllChannels[channelID].users,userName)
        AllChannels[channelID].callSign = callSign
        AllChannels[channelID].usage = usage
        AllChannels[channelID].reusable = reusable

        RegisteredUsers[userName] = channelID

        -- 添加单位移除的事件监听器
        if world then
            local oldHandler = EventHandlerPool[userName]
            if oldHandler then
                world.removeEventHandler(oldHandler)
            end

            local ev = {
                userName = userName,
            }
            function ev:onEvent(event)
                if event.id == world.event.S_EVENT_DEAD then
                    local obj = event.initiator
                    if not obj or not obj.getName or not obj.getGroup then return end

                    if Group.getByName(ev.userName) then
                        if obj.getGroup then
                            obj = obj:getGroup()
                        end
                    else
                        world.removeEventHandler(self)
                        TACANManager.deregisterChannel(self.userName)
                        return
                    end
                    if not obj then return end
                    
                    local objName = obj:getName()

                    if objName == self.userName then
                        
                        if Debug then
                            local msg = 'TACANManager - [Dead] event for: '..self.userName..' deregistering...'
                            Utils.Debug(msg)
                            env.info(msg)
                        end

                        world.removeEventHandler(self)
                        TACANManager.deregisterChannel(self.userName)
                    end
                end

                -- 通过 C_EVENT_TACAN_USER_REMOVED 事件触发注销
                if event.id == TACANManager.C_EVENT_TACAN_USER_REMOVED then
                    if not event.userName then return end

                    if event.userName == self.userName then
                        if Debug then
                            local msg = 'TACANManager - [TACAN user removed] event for: '..self.userName..' deregistering...'
                            Utils.Debug(msg)
                            env.info(msg)
                        end
                        
                        TACANManager.deregisterChannel(self.userName)
                    end
                end
            end

            world.addEventHandler(ev)
            EventHandlerPool[userName] = ev
        end

        TACANManager.DrawInfo()

        return channel
    end

    function TACANManager.deregisterChannel(userName)
        if not userName or type(userName) ~= 'string' then
            return false
        end

        local channelID = TACANManager.getUserChannelID(userName)

        if AllChannels[channelID] then
            local users = AllChannels[channelID].users
            for i, name in ipairs(users) do
                if name == userName then

                    if Debug then
                        Utils.Debug('TACANManager - deregisterChannel: '..channelID..' for '..userName)
                    end

                    local eventHandler = EventHandlerPool[userName]
                    if eventHandler then
                        world.removeEventHandler(eventHandler)
                        EventHandlerPool[userName] = nil
                        eventHandler = nil
                    end
                    RegisteredUsers[userName] = nil
                    
                    table.remove(users, i)
                    if #users == 0 then
                        AllChannels[channelID] = nil
                    end

                    TACANManager.DrawInfo()

                    return true
                end
            end
        end

        return false
    end

    --- 提供私有参数访问接口(只读)
    -- @return table TACANManager.Mode = {X='X',Y='Y'}
    function TACANManager.getChannelModeTable()
        return deepCopy(Mode)
    end

    -- @return table TACANManager.Usage = {AA='A/A',TR='T-R',REC='REC'}
    function TACANManager.getChannelUsageTable()
        return deepCopy(Usage)
    end

    -- @return table of user's channel
    function TACANManager.getUserChannelID(userName)
        if not userName or type(userName)~='string' then return nil end

        return RegisteredUsers[userName]
    end
    
    -- @return table of registered users with frequencies
    function TACANManager.getRegisteredUsers()
        
        return deepCopy(RegisteredUsers)
    end

    -- @param string TACAN channelID
    -- @return table data of the channel
    function TACANManager.getChannelDataByID(channelID)
        if not channelID then return nil end

        return deepCopy(AllChannels[channelID])
    end

    -- @return table of all registered channels
    function TACANManager.getAllChannels()
        return deepCopy(AllChannels)
    end

    -- @return boolean, if the Debug mode is on
    function TACANManager.isDebugMode()
        return Debug
    end

    ---Get radio info.
    ---@return string formatted info string for all registered channel.
    function TACANManager.getInfo()

        -- 提取已经注册的用户名[userName]
        local userNames = {}
        for userName, data in pairs(RegisteredUsers) do
            table.insert(userNames,userName)
        end
        --对 userNames 排序
        table.sort(userNames,function (a,b)
            return string.upper(a) < string.upper(b)
        end)

        -- 创建输出信息
        local info = ' TACAN:'
        for i=1,#userNames,1 do
            local userName = userNames[i]
            local data = RegisteredUsers[userName]
            if not data then break end
            
            info = info..' \n '..userName..': '..data
        end
        
        return info
    end

    --- Draw radio info on F10 map.
    function TACANManager.DrawInfo()
        if not DrawMapInfo then return end

        local info = TACANManager.getInfo()

        if not DrawInfoID then
            DrawInfoID = Utils.getMarkupID()
            trigger.action.textToAll(coalition.side.BLUE,DrawInfoID,DrawInfoCoord,{0,0,0,1},{1,1,1,0.3},12,false,info)
            -- trigger.action.markupToAll(5,DrawInfoID,coalition.side.BLUE,DrawInfoCoord,{text = info},{1,0,0,1},{1,1,0,1},1)
            return
        end

        trigger.action.setMarkupText(DrawInfoID,info)
    end
end

--Debug funcs
local function debugFuncs(vars)
    TACANManager.registerChannel(vars)

    local keys = {}
    local allChannels = TACANManager.getAllChannels()
    for k, v in pairs(allChannels) do
        table.insert(keys, k)
    end
    table.sort(keys, function(a, b)
        a = tonumber(string.sub(a,1,#a-1))
        b = tonumber(string.sub(b,1,#b-1))
        return a < b
    end)

    local function getChannelMsg(channelID)
        local msg = ''
        local data = allChannels[channelID]
        msg = msg..'\n===== '..channelID..' =====\n'
        for i,name in ipairs(data.users) do
            msg = msg..' '..i..'.'..name..' '
        end

        msg = msg..'\n Call sign: '..data.callSign
        msg = msg..'\n Usage: '..data.usage

        local reusable_msg = 'false'
        if data.reusable then
            reusable_msg = 'true'
        end

        msg = msg..'\n reusable: '..reusable_msg
        return msg
    end
    
    local text = ''

    for _, channelIdent in pairs(keys) do
        text = text.. getChannelMsg(channelIdent)
    end

    if Utils and Utils.Debug then
        Utils.Debug(text)
    end

    if log then
        env.info(text)
    end

    print(text)
end

local autoGenData = false    
if TACANManager.isDebugMode() and autoGenData then
    local testIndex = 1
    local lastUserName = nil
    local lastCallSign = nil

    if timer then
        timer.scheduleFunction(function (vars,time)
            local vars = {}
            local repeatTime = math.random(5,20)

            vars.userName = 'ts'..testIndex
            if math.random(1,10)>7 then
                vars.userName = nil
            end 
            if vars.userName then
                if math.random(1,10)>4 and lastUserName then
                    vars.userName = lastUserName
                end
                if vars.userName~=lastUserName then
                    testIndex = testIndex + 1
                end
                lastUserName = vars.userName
            end

            local alphabet = {
                'A','B','C','D','E','F',
                'R','S','T','U','V','W',
            }

            vars.callSign = alphabet[math.random(1,#alphabet)]..alphabet[math.random(1,#alphabet)]..alphabet[math.random(1,#alphabet)]
            if math.random(1,10)>7 then
                vars.callSign = nil
            end 
            if vars.callSign then
                if math.random(1,10)>7 and lastCallSign then
                    vars.callSign = lastCallSign
                end
                lastCallSign = vars.callSign
            end

            vars.channel = math.random(0,130)
            if math.random(1,10)>7 then
                vars.channel = nil
            end

            local Mode = TACANManager.getChannelModeTable()
            vars.mode = Mode.X
            if math.random(1,10)>7 then
                vars.mode = Mode.Y
            end

            local usage = TACANManager.getChannelUsageTable()
            vars.usage = usage[math.random(1,#usage)]
            if math.random(1,10)>7 then
                vars.usage = nil
            end

            vars.reusable = false
            if math.random(1,10)>7 then
                vars.reusable = true
            end

            debugFuncs(vars)
            
            return time + repeatTime
        end,{},timer.getTime()+5)
    end
end
--Debug funcs